{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'/home/ubuntu/varios/skforecast'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "import sys\n",
    "from pathlib import Path\n",
    "sys.path.insert(1, str(Path.cwd().parent))\n",
    "str(Path.cwd().parent)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Union, Tuple, Optional, Callable\n",
    "import warnings\n",
    "import logging\n",
    "import sys\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import sklearn\n",
    "from sklearn.exceptions import NotFittedError\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.base import clone\n",
    "from sklearn.preprocessing import OneHotEncoder\n",
    "from sklearn.preprocessing import OrdinalEncoder\n",
    "from copy import copy\n",
    "import inspect\n",
    "from joblib import Parallel, delayed\n",
    "\n",
    "import skforecast\n",
    "from skforecast.ForecasterAutoregMultiSeries import ForecasterAutoregMultiSeries\n",
    "from skforecast.ForecasterBase import ForecasterBase\n",
    "from skforecast.exceptions import MissingValuesWarning\n",
    "from skforecast.exceptions import IgnoredArgumentWarning\n",
    "from skforecast.utils import initialize_lags\n",
    "from skforecast.utils import initialize_weights\n",
    "from skforecast.utils import initialize_transformer_series\n",
    "from skforecast.utils import check_select_fit_kwargs\n",
    "from skforecast.utils import check_preprocess_series\n",
    "from skforecast.utils import check_preprocess_exog_multiseries\n",
    "from skforecast.utils import align_series_and_exog_multiseries\n",
    "from skforecast.utils import get_exog_dtypes\n",
    "from skforecast.utils import check_exog_dtypes\n",
    "from skforecast.utils import check_interval\n",
    "from skforecast.utils import check_predict_input\n",
    "from skforecast.utils import preprocess_last_window\n",
    "from skforecast.utils import expand_index\n",
    "from skforecast.utils import transform_series\n",
    "from skforecast.utils import transform_dataframe\n",
    "from skforecast.utils import set_skforecast_warnings\n",
    "from skforecast.preprocessing import TimeSeriesDifferentiator\n",
    "\n",
    "\n",
    "# Libraries\n",
    "# ==============================================================================\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.ensemble import RandomForestRegressor\n",
    "from sklearn.metrics import mean_absolute_error\n",
    "\n",
    "from skforecast.datasets import fetch_dataset\n",
    "from skforecast.ForecasterAutoregMultiSeries import ForecasterAutoregMultiSeries\n",
    "from skforecast.model_selection_multiseries import backtesting_forecaster_multiseries\n",
    "from skforecast.model_selection_multiseries import grid_search_forecaster_multiseries\n",
    "from skforecast.model_selection_multiseries import bayesian_search_forecaster_multiseries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "forecaster = ForecasterAutoregMultiSeries(\n",
    "                 regressor          = RandomForestRegressor(random_state=123),\n",
    "                 lags               = 3,\n",
    "                 encoding           = 'ordinal',\n",
    "                 transformer_series = StandardScaler(),\n",
    "                 transformer_exog   = None,\n",
    "                 weight_func        = None,\n",
    "                 series_weights     = None,\n",
    "                 differentiation    = None,\n",
    "                 dropna_from_series = False,\n",
    "                 fit_kwargs         = None,\n",
    "                 forecaster_id      = None\n",
    "             )\n",
    "\n",
    "self = forecaster"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def _create_train_X_y(\n",
    "        self,\n",
    "        series: Union[pd.DataFrame, dict],\n",
    "        exog: Optional[Union[pd.Series, pd.DataFrame, dict]]=None,\n",
    "        store_last_window: Union[bool, list]=True,\n",
    "        parallel: bool=False\n",
    "    ) -> Tuple[pd.DataFrame, pd.Series, dict, list, list, list, dict, dict]:\n",
    "        \"\"\"\n",
    "        Create training matrices from multiple time series and exogenous\n",
    "        variables. See Notes section for more details depending on the type of\n",
    "        `series` and `exog`.\n",
    "        \n",
    "        Parameters\n",
    "        ----------\n",
    "        series : pandas DataFrame, dict\n",
    "            Training time series.\n",
    "        exog : pandas Series, pandas DataFrame, dict, default `None`\n",
    "            Exogenous variable/s included as predictor/s.\n",
    "        store_last_window : bool, list, default `True`\n",
    "            Whether or not to store the last window of training data.\n",
    "\n",
    "            - If `True`, last_window is stored for all series. \n",
    "            - If `list`, last_window is stored for the series present in the list.\n",
    "            - If `False`, last_window is not stored.\n",
    "\n",
    "        Returns\n",
    "        -------\n",
    "        X_train : pandas DataFrame\n",
    "            Training values (predictors).\n",
    "        y_train : pandas Series\n",
    "            Values (target) of the time series related to each row of `X_train`.\n",
    "        series_indexes : dict\n",
    "            Dictionary with the index of each series.\n",
    "        series_col_names : list\n",
    "            Names of the series (levels) provided by the user during training.\n",
    "        series_X_train : list\n",
    "            Names of the series (levels) included in the matrix `X_train` created\n",
    "            internally for training. It can be different from `series_col_names` if\n",
    "            some series are dropped during the training process because of NaNs or\n",
    "            because they are not present in the training period.\n",
    "        exog_col_names : list\n",
    "            Names of the exogenous variables used during training.\n",
    "        exog_dtypes : dict\n",
    "            Type of each exogenous variable/s used in training. If `transformer_exog` \n",
    "            is used, the dtypes are calculated before the transformation.\n",
    "        last_window : dict\n",
    "            Last window of training data for each series. It stores the values \n",
    "            needed to predict the next `step` immediately after the training data.\n",
    "\n",
    "        Notes\n",
    "        -----\n",
    "        - If `series` is a pandas DataFrame and `exog` is a pandas Series or \n",
    "        DataFrame, each exog is duplicated for each series. Exog must have the\n",
    "        same index as `series` (type, length and frequency).\n",
    "        - If `series` is a pandas DataFrame and `exog` is a dict of pandas Series \n",
    "        or DataFrames. Each key in `exog` must be a column in `series` and the \n",
    "        values are the exog for each series. Exog must have the same index as \n",
    "        `series` (type, length and frequency).\n",
    "        - If `series` is a dict of pandas Series, `exog` must be a dict of pandas\n",
    "        Series or DataFrames. The keys in `series` and `exog` must be the same.\n",
    "        All series and exog must have a pandas DatetimeIndex with the same \n",
    "        frequency.\n",
    "        \n",
    "        \"\"\"\n",
    "\n",
    "        series_dict, series_indexes = check_preprocess_series(series=series)\n",
    "        input_series_is_dict = isinstance(series, dict)\n",
    "        series_col_names = list(series_dict.keys())\n",
    "\n",
    "        if self.fitted and not (series_col_names == self.series_col_names):\n",
    "            raise ValueError(\n",
    "                (f\"Once the Forecaster has been trained, `series` must have the \"\n",
    "                 f\"same columns as the series used during training:\\n\" \n",
    "                 f\" Got      : {series_col_names}\\n\"\n",
    "                 f\" Expected : {self.series_col_names}\")\n",
    "            )\n",
    "\n",
    "        exog_dict = {serie: None for serie in series_col_names}\n",
    "        exog_col_names = None\n",
    "        if exog is not None:\n",
    "            exog_dict, exog_col_names = check_preprocess_exog_multiseries(\n",
    "                                            input_series_is_dict = input_series_is_dict,\n",
    "                                            series_indexes       = series_indexes,\n",
    "                                            series_col_names     = series_col_names,\n",
    "                                            exog                 = exog,\n",
    "                                            exog_dict            = exog_dict\n",
    "                                        )\n",
    "\n",
    "            if self.fitted:\n",
    "                if self.exog_col_names is None:\n",
    "                    raise ValueError(\n",
    "                        (\"Once the Forecaster has been trained, `exog` must be `None` \"\n",
    "                         \"because no exogenous variables were added during training.\")\n",
    "                    )\n",
    "                else:\n",
    "                    if not set(exog_col_names) == set(self.exog_col_names):\n",
    "                        raise ValueError(\n",
    "                            (f\"Once the Forecaster has been trained, `exog` must have the \"\n",
    "                             f\"same columns as the series used during training:\\n\" \n",
    "                             f\" Got      : {exog_col_names}\\n\"\n",
    "                             f\" Expected : {self.exog_col_names}\")\n",
    "                        )\n",
    "\n",
    "        if not self.fitted:\n",
    "            self.transformer_series_ = initialize_transformer_series(\n",
    "                                           series_col_names = series_col_names,\n",
    "                                           transformer_series = self.transformer_series\n",
    "                                       )\n",
    "\n",
    "        if self.differentiation is None:\n",
    "            self.differentiator_ = {serie: None for serie in series_col_names}\n",
    "        else:\n",
    "            if not self.fitted:\n",
    "                self.differentiator_ = {serie: clone(self.differentiator) \n",
    "                                        for serie in series_col_names}\n",
    "\n",
    "        series_dict, exog_dict = align_series_and_exog_multiseries(\n",
    "                                     series_dict          = series_dict,\n",
    "                                     input_series_is_dict = input_series_is_dict,\n",
    "                                     exog_dict            = exog_dict\n",
    "                                 )\n",
    "\n",
    "        ignore_exog = True if exog is None else False\n",
    "        input_matrices = [\n",
    "            [series_dict[k], exog_dict[k], ignore_exog]\n",
    "             for k in series_dict.keys()\n",
    "        ]\n",
    "\n",
    "        if not parallel:\n",
    "            # ======================================================================\n",
    "            X_train_lags_buffer = []\n",
    "            X_train_exog_buffer = []\n",
    "            y_train_buffer = []\n",
    "            for matrices in input_matrices:\n",
    "\n",
    "                X_train_lags, X_train_exog, y_train = (\n",
    "                    self._create_train_X_y_single_series(\n",
    "                        y           = matrices[0],\n",
    "                        exog        = matrices[1],\n",
    "                        ignore_exog = matrices[2],\n",
    "                    )\n",
    "                )\n",
    "\n",
    "                X_train_lags_buffer.append(X_train_lags)\n",
    "                X_train_exog_buffer.append(X_train_exog)\n",
    "                y_train_buffer.append(y_train)\n",
    "            # ======================================================================\n",
    "        else:\n",
    "            def process_matrices(matrices):\n",
    "                return self._create_train_X_y_single_series(\n",
    "                            y           = matrices[0],\n",
    "                            exog        = matrices[1],\n",
    "                            ignore_exog = matrices[2],\n",
    "                        )\n",
    "\n",
    "            results = Parallel(n_jobs=-1)(delayed(process_matrices)(matrices) for matrices in input_matrices)\n",
    "            X_train_lags_buffer, X_train_exog_buffer, y_train_buffer = zip(*results)\n",
    "\n",
    "        X_train = pd.concat(X_train_lags_buffer, axis=0)\n",
    "        y_train = pd.concat(y_train_buffer, axis=0)\n",
    "\n",
    "        if self.fitted:\n",
    "            encoded_values = self.encoder.transform(X_train[['_level_skforecast']])\n",
    "        else:\n",
    "            encoded_values = self.encoder.fit_transform(X_train[['_level_skforecast']])\n",
    "            for i, code in enumerate(self.encoder.categories_[0]):\n",
    "                self.encoding_mapping[code] = i\n",
    "\n",
    "        X_train = pd.concat([\n",
    "                      X_train.drop(columns='_level_skforecast'),\n",
    "                      encoded_values\n",
    "                  ], axis=1)\n",
    "\n",
    "        if self.encoding == 'onehot':\n",
    "            X_train.columns = X_train.columns.str.replace('_level_skforecast_', '')\n",
    "        elif self.encoding == 'ordinal_category':\n",
    "            X_train['_level_skforecast'] = (\n",
    "                X_train['_level_skforecast'].astype('category')\n",
    "            )\n",
    "\n",
    "        del encoded_values\n",
    "\n",
    "        exog_dtypes = None\n",
    "        if exog is not None:\n",
    "\n",
    "            X_train_exog = pd.concat(X_train_exog_buffer, axis=0)\n",
    "            if '_dummy_exog_col_to_keep_shape' in X_train_exog.columns:\n",
    "                X_train_exog = (\n",
    "                    X_train_exog.drop(columns=['_dummy_exog_col_to_keep_shape'])\n",
    "                )\n",
    "\n",
    "            exog_col_names = X_train_exog.columns.to_list()\n",
    "            exog_dtypes = get_exog_dtypes(exog=X_train_exog)\n",
    "\n",
    "            fit_transformer = False if self.fitted else True\n",
    "            X_train_exog = transform_dataframe(\n",
    "                               df                = X_train_exog,\n",
    "                               transformer       = self.transformer_exog,\n",
    "                               fit               = fit_transformer,\n",
    "                               inverse_transform = False\n",
    "                           )\n",
    "\n",
    "            check_exog_dtypes(X_train_exog, call_check_exog=False)\n",
    "            if not (X_train_exog.index == X_train.index).all():\n",
    "                raise ValueError(\n",
    "                    (\"Different index for `series` and `exog` after transformation. \"\n",
    "                     \"They must be equal to ensure the correct alignment of values.\")\n",
    "                )\n",
    "\n",
    "            X_train = pd.concat([X_train, X_train_exog], axis=1)\n",
    "\n",
    "        if y_train.isnull().any():\n",
    "            mask = y_train.notna().to_numpy()\n",
    "            y_train = y_train.iloc[mask]\n",
    "            X_train = X_train.iloc[mask,]\n",
    "            warnings.warn(\n",
    "                (\"NaNs detected in `y_train`. They have been dropped because the \"\n",
    "                 \"target variable cannot have NaN values. Same rows have been \"\n",
    "                 \"dropped from `X_train` to maintain alignment. This is caused by \"\n",
    "                 \"series with interspersed NaNs.\"),\n",
    "                 MissingValuesWarning\n",
    "            )\n",
    "\n",
    "        if self.dropna_from_series:\n",
    "            if X_train.isnull().any().any():\n",
    "                mask = X_train.notna().all(axis=1).to_numpy()\n",
    "                X_train = X_train.iloc[mask, ]\n",
    "                y_train = y_train.iloc[mask]\n",
    "                warnings.warn(\n",
    "                    (\"NaNs detected in `X_train`. They have been dropped. If \"\n",
    "                     \"you want to keep them, set `forecaster.dropna_from_series = False`. \" \n",
    "                     \"Same rows have been removed from `y_train` to maintain alignment. \"\n",
    "                     \"This caused by series with interspersed NaNs.\"),\n",
    "                     MissingValuesWarning\n",
    "                )\n",
    "        else:\n",
    "            if X_train.isnull().any().any():\n",
    "                warnings.warn(\n",
    "                    (\"NaNs detected in `X_train`. Some regressors do not allow \"\n",
    "                     \"NaN values during training. If you want to drop them, \"\n",
    "                     \"set `forecaster.dropna_from_series = True`.\"),\n",
    "                     MissingValuesWarning\n",
    "                )\n",
    "\n",
    "        if X_train.empty:\n",
    "            raise ValueError(\n",
    "                (\"All samples have been removed due to NaNs. Set \"\n",
    "                 \"`forecaster.dropna_from_series = False` or review `exog` values.\")\n",
    "            )\n",
    "        \n",
    "        if self.encoding == 'onehot':\n",
    "            series_X_train = [\n",
    "                col for col in series_col_names if X_train[col].sum() > 0\n",
    "            ]\n",
    "        else:\n",
    "            series_X_train = [\n",
    "                k for k, v in self.encoding_mapping.items()\n",
    "                if v in X_train['_level_skforecast'].unique()\n",
    "            ]\n",
    "\n",
    "        # The last time window of training data is stored so that lags needed as\n",
    "        # predictors in the first iteration of `predict()` can be calculated.\n",
    "        last_window = None\n",
    "        if store_last_window:\n",
    "\n",
    "            series_to_store = (\n",
    "                series_X_train if store_last_window is True else store_last_window\n",
    "            )\n",
    "\n",
    "            series_not_in_series_dict = set(series_to_store) - set(series_X_train)\n",
    "            if series_not_in_series_dict:\n",
    "                warnings.warn(\n",
    "                    (f\"Series {series_not_in_series_dict} are not present in \"\n",
    "                     f\"`series`. No last window is stored for them.\"),\n",
    "                    IgnoredArgumentWarning\n",
    "                )\n",
    "                series_to_store = [s for s in series_to_store \n",
    "                                   if s not in series_not_in_series_dict]\n",
    "\n",
    "            if series_to_store:\n",
    "                last_window = {\n",
    "                    k: v.iloc[-self.window_size_diff:].copy()\n",
    "                    for k, v in series_dict.items()\n",
    "                    if k in series_to_store\n",
    "                }\n",
    "\n",
    "        return (\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Length of each series: 1097\n"
     ]
    }
   ],
   "source": [
    "data = fetch_dataset(name=\"items_sales\", verbose=False)\n",
    "data_100 = pd.concat([data]*33, axis=1)\n",
    "data_100.columns = [f'serie_{i}' for i in range(data_100.shape[1])]\n",
    "data_1000 = pd.concat([data]*333, axis=1)\n",
    "data_1000.columns = [f'serie_{i}' for i in range(data_1000.shape[1])]\n",
    "print(f\"Length of each series: {len(data)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "14.4 ms ± 326 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data, exog=None, store_last_window=True, parallel=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The slowest run took 48.25 times longer than the fastest. This could mean that an intermediate result is being cached.\n",
      "260 ms ± 379 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data, exog=None, store_last_window=True, parallel=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "434 ms ± 978 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data_100, exog=None, store_last_window=True, parallel=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "357 ms ± 6.15 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data_100, exog=None, store_last_window=True, parallel=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "11.2 s ± 66.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data_1000, exog=None, store_last_window=True, parallel=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10.6 s ± 169 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data_1000, exog=None, store_last_window=True, parallel=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Length of each series: 5485\n"
     ]
    }
   ],
   "source": [
    "data = fetch_dataset(name=\"items_sales\", verbose=False)\n",
    "data = pd.concat([data, data, data, data, data])\n",
    "data.index = pd.date_range(start=data.index.min(), periods=len(data), freq=data.index.freq)\n",
    "\n",
    "data_100 = pd.concat([data]*33, axis=1)\n",
    "data_100.columns = [f'serie_{i}' for i in range(data_100.shape[1])]\n",
    "data_1000 = pd.concat([data]*333, axis=1)\n",
    "data_1000.columns = [f'serie_{i}' for i in range(data_1000.shape[1])]\n",
    "print(f\"Length of each series: {len(data)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "178 ms ± 1.75 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data, exog=None, store_last_window=True, parallel=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "185 ms ± 1.41 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data, exog=None, store_last_window=True, parallel=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4.19 s ± 3.41 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data_100, exog=None, store_last_window=True, parallel=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4.19 s ± 21.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data_100, exog=None, store_last_window=True, parallel=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "41.9 s ± 256 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data_1000, exog=None, store_last_window=True, parallel=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "42 s ± 319 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "            X_train,\n",
    "            y_train,\n",
    "            series_indexes,\n",
    "            series_col_names,\n",
    "            series_X_train,\n",
    "            exog_col_names,\n",
    "            exog_dtypes,\n",
    "            last_window,\n",
    "        ) = _create_train_X_y(self, data_1000, exog=None, store_last_window=True, parallel=True)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "skforecast_py10",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "c78d62c1713fdacd99ef7c429003c7324b36fbb551fb8b6860a7ea73e9338235"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
